package com.ruoyi.prescription.service.impl;

import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.employee.domain.Employee;
import com.ruoyi.employee.service.IEmployeeService;
import com.ruoyi.medication.domain.Medication;
import com.ruoyi.medication.mapper.MedicationMapper;
import com.ruoyi.prescription.domain.Prescription;
import com.ruoyi.prescription.domain.PrescriptionDetail;
import com.ruoyi.prescription.mapper.PrescriptionMapper;
import com.ruoyi.prescription.service.IPrescriptionService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.medication.service.IMedicationStockService;
import com.ruoyi.medication.domain.MedicationStock;
import com.ruoyi.system.service.ISysNoticeService;
import com.ruoyi.system.domain.SysNotice;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.patients.domain.Patients;
import com.ruoyi.patients.service.IPatientsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 处方Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-04-12
 */
@Service
public class PrescriptionServiceImpl implements IPrescriptionService {
    private static final Logger log = LoggerFactory.getLogger(PrescriptionServiceImpl.class);

    @Autowired
    private PrescriptionMapper prescriptionMapper;

    @Autowired
    private IEmployeeService employeeService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private IMedicationStockService medicationStockService;

    @Autowired
    private ISysNoticeService noticeService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private IPatientsService patientsService;

    @Autowired
    private MedicationMapper medicationMapper;

    /**
     * 判断当前用户是否为医生角色
     * 
     * @return 是否为医生
     */
    private boolean isDoctorRole() {
        // 获取当前登录用户
        SysUser currentUser = SecurityUtils.getLoginUser().getUser();

        // 查询用户角色
        List<SysRole> roles = roleService.selectRolesByUserId(currentUser.getUserId());

        // // 判断是否有医生角色
        // for (SysRole role : roles) {
        // if ("doctor".equals(role.getRoleKey())) {
        // return true;
        // }
        // }
        if (roles.get(0).equals("doctor")) {
            return true;
        }

        return false;
    }

    /**
     * 获取当前医生的员工ID
     * 
     * @return 员工ID
     */
    private Long getCurrentDoctorEmployeeId() {
        // 获取当前登录用户
        SysUser currentUser = SecurityUtils.getLoginUser().getUser();

        // 查询当前用户对应的员工信息
        Employee employee = new Employee();
        employee.setUser(currentUser.getUserName());
        List<Employee> employees = employeeService.selectEmployeeList(employee);

        if (!employees.isEmpty()) {
            return employees.get(0).getId();
        }

        return null;
    }

    /**
     * 查询处方
     * 
     * @param id 处方主键
     * @return 处方
     */
    @Override
    public Prescription selectPrescriptionById(Long id) {
        // 如果是医生角色,则需要验证该处方是否属于当前医生
        if (isDoctorRole()) {
            Long employeeId = getCurrentDoctorEmployeeId();
            if (employeeId != null) {
                Prescription prescription = prescriptionMapper.selectPrescriptionById(id);
                if (prescription != null && !prescription.getEmployeeId().equals(employeeId)) {
                    throw new ServiceException("无权访问该处方信息");
                }
            }
        }

        return prescriptionMapper.selectPrescriptionById(id);
    }

    /**
     * 查询处方列表
     * 
     * @param prescription 处方
     * @return 处方
     */
    @Override
    public List<Prescription> selectPrescriptionList(Prescription prescription) {
        // // 如果是医生角色,则只查询该医生的处方
        // if (isDoctorRole()) {
        // Long employeeId = getCurrentDoctorEmployeeId();
        // if (employeeId != null) {
        // prescription.setEmployeeId(employeeId);
        // }
        // }
        return prescriptionMapper.selectPrescriptionList(prescription);
    }

    /**
     * 新增处方
     * 
     * @param prescription 处方
     * @return 结果
     */
    @Transactional
    @Override
    public int insertPrescription(Prescription prescription) {
        // 如果是医生角色,则设置处方的医生ID为当前医生
        if (isDoctorRole()) {
            Long employeeId = getCurrentDoctorEmployeeId();
            if (employeeId != null) {
                prescription.setEmployeeId(employeeId);
            }
        }

        prescription.setStatus("1");
        prescription.setCreateTime(DateUtils.getNowDate());
        prescription.setUpdateTime(DateUtils.getNowDate());
        int rows = prescriptionMapper.insertPrescription(prescription);
        insertPrescriptionDetail(prescription);
        return rows;
    }

    /**
     * 修改处方
     * 
     * @param prescription 处方
     * @return 结果
     */
    @Transactional
    @Override
    public int updatePrescription(Prescription prescription) {
//        // 如果是医生角色,则需要验证该处方是否属于当前医生
//        if (isDoctorRole()) {
//            Long employeeId = getCurrentDoctorEmployeeId();
//            if (employeeId != null) {
//                Prescription existingPrescription = prescriptionMapper.selectPrescriptionById(prescription.getId());
//                if (existingPrescription != null && !existingPrescription.getEmployeeId().equals(employeeId)) {
//                    throw new ServiceException("无权修改该处方信息");
//                }
//                prescription.setEmployeeId(employeeId);
//            }
//        }

        // 获取原处方明细，用于恢复库存
        if (prescription.getStatus().equals("2")) {
            Prescription oldPrescription = prescriptionMapper.selectPrescriptionById(prescription.getId());
            if (oldPrescription != null && oldPrescription.getPrescriptionDetailList() != null) {
                for (PrescriptionDetail detail : oldPrescription.getPrescriptionDetailList()) {
                    updateMedicationStock(detail.getMedicationId(), detail.getQuantity());
                }
            }
        }
        return prescriptionMapper.updatePrescription(prescription);
    }

    /**
     * 批量删除处方
     * 
     * @param ids 需要删除的处方主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deletePrescriptionByIds(Long[] ids) {
        // 如果是医生角色,则需要验证这些处方是否都属于当前医生
        if (isDoctorRole()) {
            Long employeeId = getCurrentDoctorEmployeeId();
            if (employeeId != null) {
                for (Long id : ids) {
                    Prescription prescription = prescriptionMapper.selectPrescriptionById(id);
                    if (prescription != null && !prescription.getEmployeeId().equals(employeeId)) {
                        throw new ServiceException("无权删除处方ID为" + id + "的处方信息");
                    }
                }
            }
        }

        prescriptionMapper.deletePrescriptionDetailByPrescriptionIds(ids);
        return prescriptionMapper.deletePrescriptionByIds(ids);
    }

    /**
     * 删除处方信息
     * 
     * @param id 处方主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deletePrescriptionById(Long id) {
        // 如果是医生角色,则需要验证该处方是否属于当前医生
        if (isDoctorRole()) {
            Long employeeId = getCurrentDoctorEmployeeId();
            if (employeeId != null) {
                Prescription prescription = prescriptionMapper.selectPrescriptionById(id);
                if (prescription != null && !prescription.getEmployeeId().equals(employeeId)) {
                    throw new ServiceException("无权删除该处方信息");
                }
            }
        }

        prescriptionMapper.deletePrescriptionDetailByPrescriptionId(id);
        return prescriptionMapper.deletePrescriptionById(id);
    }

    /**
     * 更新药品库存
     * 
     * @param medicationId 药品ID
     * @param quantity     需要扣减的数量
     */
    private void updateMedicationStock(Long medicationId, Long quantity) {
        // 更新药品库存
        List<MedicationStock> allStocks = medicationStockService
                .selectMedicationStockByMedicationId(medicationId);
        if (allStocks == null || allStocks.isEmpty()) {
            throw new ServiceException("未找到药品库存信息，药品ID：" + medicationId);
        }

        // 计算需要扣减的数量
        Long remainingQuantity = quantity;

        // 遍历所有库存记录，按过期日期升序处理
        for (MedicationStock stock : allStocks) {
            if (remainingQuantity <= 0) {
                break;
            }

            // 跳过库存为0的记录
            if (stock.getQuantity() <= 0) {
                continue;
            }

            // 如果当前库存记录的数量足够
            if (stock.getQuantity() >= remainingQuantity) {
                stock.setQuantity(stock.getQuantity() - remainingQuantity);
                medicationStockService.updateMedicationStock(stock);
                remainingQuantity = 0L;
            } else {
                // 如果当前库存记录的数量不足，全部使用并继续处理下一条记录
                remainingQuantity -= stock.getQuantity();
                stock.setQuantity(0L);
                medicationStockService.updateMedicationStock(stock);
            }
        }

        // 如果所有库存记录都处理完了，但还有剩余数量需要扣减
        if (remainingQuantity > 0) {
            throw new ServiceException("药品库存不足，药品ID：" + medicationId);
        }
    }

    /**
     * 新增处方明细信息
     * 
     * @param prescription 处方对象
     */
    public void insertPrescriptionDetail(Prescription prescription) {
        List<PrescriptionDetail> prescriptionDetailList = prescription.getPrescriptionDetailList();
        Long id = prescription.getId();
        if (StringUtils.isNotNull(prescriptionDetailList)) {
            List<PrescriptionDetail> list = new ArrayList<PrescriptionDetail>();
            for (PrescriptionDetail prescriptionDetail : prescriptionDetailList) {
                prescriptionDetail.setPrescriptionId(id);
                list.add(prescriptionDetail);
            }
            if (list.size() > 0) {
                prescriptionMapper.batchPrescriptionDetail(list);
            }
        }
    }

    /**
     * 自动审核处方
     * 每1分钟检查一次，将创建时间超过3分钟的"审核中"处方自动设置为"治疗中"
     */
    @Scheduled(fixedRate = 60000) // 每1分钟执行一次
    public void autoCheckPrescription() {
        // 查询所有状态为"审核中"的处方
        Prescription query = new Prescription();
        query.setStatus("1"); // 1 表示审核中
        List<Prescription> prescriptions = prescriptionMapper.selectPrescriptionList(query);

        // 获取当前时间
        Date now = new Date();

        // 遍历处方列表
        for (Prescription prescription : prescriptions) {
            // 计算处方创建时间到现在的分钟数
            long minutes = TimeUnit.MILLISECONDS.toMinutes(
                    now.getTime() - prescription.getCreateTime().getTime());

            // 如果超过3分钟，自动设置为治疗中
            if (minutes >= 3) {
                prescription.setStatus("2"); // 2 表示治疗中
                prescription.setUpdateTime(now);
                updatePrescription(prescription);
            }
        }
    }

    /**
     * 自动完成处方
     * 每1分钟检查一次，将创建时间超过5天的"治疗中"处方自动设置为"已完成"
     */
    @Scheduled(fixedRate = 60000) // 每1分钟执行一次
    public void autoCompletePrescription() {
        // 查询所有状态为"治疗中"的处方
        Prescription query = new Prescription();
        query.setStatus("2"); // 2 表示治疗中
        List<Prescription> prescriptions = prescriptionMapper.selectPrescriptionList(query);

        // 获取当前时间
        Date now = new Date();

        // 遍历处方列表
        for (Prescription prescription : prescriptions) {
            // 计算处方创建时间到现在的天数
            long days = TimeUnit.MILLISECONDS.toDays(
                    now.getTime() - prescription.getCreateTime().getTime());

            // 如果超过5天，自动设置为已完成
            if (days >= 5) {
                prescription.setStatus("3"); // 3 表示已完成
                prescription.setUpdateTime(now);
                prescriptionMapper.updatePrescription(prescription);
            }
        }
    }

    /**
     * 发送用药提醒
     * 每天6点、12点、21点执行
     */
    // @Scheduled(fixedRate = 600000)
    @Scheduled(cron = "0 0 8,14,20 * * ?")
    public void sendMedicationReminder() {
        // 查询所有状态为"治疗中"的处方
        Prescription query = new Prescription();
        query.setStatus("2"); // 2 表示治疗中
        List<Prescription> prescriptions = prescriptionMapper.selectPrescriptionList(query);

        // 获取当前时间
        Date now = new Date();

        // 遍历处方列表
        for (Prescription prescription : prescriptions) {
            // 获取完整的处方信息，包括明细
            Prescription fullPrescription = prescriptionMapper.selectPrescriptionById(prescription.getId());

            // 根据患者ID获取患者信息
            Patients patient = patientsService.selectPatientsById(fullPrescription.getPatientsId());
            if (patient == null || StringUtils.isEmpty(patient.getUser())) {
                continue; // 跳过没有关联用户的患者
            }

            // 根据用户名查找系统用户
            SysUser sysUser = userService.selectUserByUserName(patient.getUser());
            if (sysUser == null) {
                continue; // 跳过没有找到系统用户的患者
            }

            // 创建用药提醒通知
            SysNotice notice = new SysNotice();
            notice.setNoticeTitle("用药提醒");
            notice.setNoticeType("1"); // 1 表示通知
            notice.setStatus("0"); // 0 表示正常
            notice.setCreateTime(now);
            notice.setCreateBy(sysUser.getUserId().toString()); // 使用createBy字段存储用户ID

            // 构建通知内容
            StringBuilder content = new StringBuilder();
            content.append("尊敬的").append(patient.getName()).append("患者：\n");
            content.append("您当前有正在进行的处方治疗，请按时服药。\n");
            content.append("处方ID：").append(fullPrescription.getId()).append("\n");
            content.append("开方时间：")
                    .append(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", fullPrescription.getCreateTime()))
                    .append("\n");
            content.append("当前状态：治疗中\n\n");

            // 添加处方明细信息
            content.append("用药明细：\n");
            if (fullPrescription.getPrescriptionDetailList() != null) {
                for (PrescriptionDetail detail : fullPrescription.getPrescriptionDetailList()) {
                    content.append("- 药品ID：").append(detail.getMedicationId())
                            .append("，剂量：").append(detail.getDosage())
                            .append("，数量：").append(detail.getQuantity()).append("\n");
                }
            }

            notice.setNoticeContent(content.toString());

            // 保存通知
            noticeService.insertNotice(notice);
        }
    }

    @Override
    public int remindMedication(Long id) {
        // 获取处方信息
        Prescription prescription = prescriptionMapper.selectPrescriptionById(id);
        if (prescription == null) {
            throw new ServiceException("处方不存在");
        }

        // 根据患者ID获取患者信息
        Patients patient = patientsService.selectPatientsById(prescription.getPatientsId());
        if (patient == null || StringUtils.isEmpty(patient.getUser())) {
            throw new ServiceException("未找到患者信息或患者未关联系统账号");
        }

        // 根据用户名查找系统用户
        SysUser sysUser = userService.selectUserByUserName(patient.getUser());
        if (sysUser == null) {
            throw new ServiceException("未找到患者对应的系统账号");
        }

        // 创建用药提醒通知
        SysNotice notice = new SysNotice();
        notice.setNoticeTitle("用药提醒");
        notice.setNoticeType("1");
        notice.setStatus("0");
        notice.setCreateBy(sysUser.getUserId().toString()); // 使用createBy字段存储用户ID
        notice.setCreateTime(new Date());

        // 构建通知内容
        StringBuilder content = new StringBuilder();
        content.append("尊敬的").append(patient.getName()).append("患者：\n");
        content.append("您当前有正在进行的处方治疗，请按时服药。\n");
        content.append("处方ID：").append(prescription.getId()).append("\n");
        content.append("开方时间：")
                .append(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", prescription.getCreateTime()))
                .append("\n");
        content.append("当前状态：").append(prescription.getStatus()).append("\n\n");
        content.append("用药信息：\n");

        // 获取处方明细
        List<PrescriptionDetail> details = prescription.getPrescriptionDetailList();
        if (details != null && !details.isEmpty()) {
            for (PrescriptionDetail detail : details) {
                Medication medication = medicationMapper.selectMedicationById(detail.getMedicationId());
                content.append("- 药品名称: ").append(medication.getName())
                        .append(", 剂量: ").append(detail.getDosage())
                        .append(", 数量: ").append(detail.getQuantity()).append("\n");
            }
        }

        notice.setNoticeContent(content.toString());
        return noticeService.insertNotice(notice);
    }

    /**
     * 获取未读用药提醒
     */
    @Override
    public List<SysNotice> getUnreadReminders() {
        // 获取当前登录用户
        Long userId = SecurityUtils.getUserId();

        SysNotice notice = new SysNotice();
        notice.setNoticeType("1"); // 通知类型
        notice.setStatus("0"); // 正常状态
        notice.setNoticeTitle("用药提醒"); // 用药提醒标题
        notice.setCreateBy(userId.toString()); // 使用createBy字段存储用户ID
        return noticeService.selectNoticeList(notice);
    }

    /**
     * 删除3小时前的用药提醒通知
     */
    @Scheduled(fixedRate = 60000) // 每分钟执行一次
    public void deleteOldMedicationReminders() {
        try {
            // 获取3小时前的时间
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.HOUR, -3);
            Date threeHoursAgo = calendar.getTime();

            // 创建查询条件
            SysNotice notice = new SysNotice();
            notice.setNoticeType("1"); // 通知类型
            notice.setNoticeTitle("用药提醒"); // 用药提醒标题
            notice.setStatus("0"); // 正常状态

            // 获取所有用药提醒通知
            List<SysNotice> notices = noticeService.selectNoticeList(notice);

            // 遍历通知，删除3小时前的
            for (SysNotice n : notices) {
                if (n.getCreateTime().before(threeHoursAgo)) {
                    noticeService.deleteNoticeById(n.getNoticeId());
                }
            }
        } catch (Exception e) {
            log.error("删除过期用药提醒通知失败", e);
        }
    }
}
